#ifndef __MESSAGE_H__
#define __MESSAGE_H__

#include <set>
#include "defer-internal.h"
#include "common.h"

class Message;
class MessageHandler;

class MessageHandler {
public:
	virtual ~MessageHandler();

	virtual void OnMessage(Message *pmsg) = 0;

private:
	std::set<Message*> message_set_;
	friend class Message;
};

// Derive from this for specialized data
// App manages lifetime, except when messages are purged

class MessageData {
public:
	MessageData() {}
	virtual ~MessageData() {}
};

template <class T>
class TypedMessageData : public MessageData {
public:
	TypedMessageData(const T& data) : data_(data) { }
	const T& data() const { return data_; }
	T& data() { return data_; }
private:
	T data_;
};

template<class T>
inline MessageData* WrapMessageData(const T& data) {
	return new TypedMessageData<T>(data);
}

template<class T>
inline const T& UseMessageData(MessageData* data) {
	return static_cast< TypedMessageData<T>* >(data)->data();
}

template<class T>
class DisposeData : public MessageData {
public:
	DisposeData(T* data) : data_(data) { }
	virtual ~DisposeData() { delete data_; }
private:
	T* data_;
};

const uint32 MQID_ANY = static_cast<uint32>(-1);
const uint32 MQID_DISPOSE = static_cast<uint32>(-2);


class Message 
{
public:
	Message() {
		memset(this, 0, sizeof(*this));//take care of this kind of initialization, virtual pointer
	}

	void Post();

	deferred_cb deferred_;
	MessageHandler *phandler;
	uint32 message_id;
	MessageData *pdata;
}; 

template<class T> void Dispose(T* doomed) 
{
	if (doomed) {
		Message * pMsg = new Message();
		pMsg->phandler = NULL;
		pMsg->message_id = MQID_DISPOSE;
		pMsg->pdata = new DisposeData<T>(doomed);
		pMsg->Post();
	}
}

#endif//__MESSAGE_H__